package top.lyunk.demo.es;

import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.mapping.Property;
import co.elastic.clients.elasticsearch.core.GetResponse;
import co.elastic.clients.elasticsearch.core.IndexResponse;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.elasticsearch.indices.CreateIndexResponse;
import co.elastic.clients.elasticsearch.indices.DeleteAliasResponse;
import co.elastic.clients.elasticsearch.indices.DeleteIndexResponse;
import co.elastic.clients.json.jackson.JacksonJsonpMapper;
import co.elastic.clients.transport.ElasticsearchTransport;
import co.elastic.clients.transport.rest_client.RestClientTransport;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.github.jsonzou.jmockdata.JMockData;
import com.github.jsonzou.jmockdata.MockConfig;
import lombok.Data;
import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;

import java.io.IOException;
import java.time.LocalDate;
import java.util.Map;

public class DemoESClient {
    public static void main(String[] args) throws IOException, InterruptedException {
        ObjectMapper om = new ObjectMapper();
        om.registerModule(new JavaTimeModule());


        // Create the low-level client
        RestClient restClient = RestClient.builder(
                new HttpHost("localhost", 9200)).build();

        // Create the transport with a Jackson mapper
        ElasticsearchTransport transport = new RestClientTransport(
                restClient, new JacksonJsonpMapper(om));

        // And create the API client
        ElasticsearchClient client = new ElasticsearchClient(transport);

        try {
            createIndex(client);
            System.out.println("================================================");
            // 增
            String id = addDocument(client);
            Thread.sleep(1000);
            System.out.println("================================================");
            getDocument(client, id);
            System.out.println("================================================");
            for (int i = 0; i < 10; i++) {
                addDocument(client);
            }
            Thread.sleep(1000);
            // 删
            // 改
            // 查
            getDocument(client, id);
            System.out.println("================================================");
            searchDocument(client);
            System.out.println("================================================");
            // 聚合
            aggregation(client);
        } finally {
            deleteIndex(client);
        }

        restClient.close();
    }

    private static void aggregation(ElasticsearchClient client) throws IOException {
        SearchResponse<Employer> search = client.search(r -> r
                        .index("employer-demo")
                        .aggregations("group_by_age", aggr -> aggr
                                .terms(term -> term
                                        .field("age")))
                , Employer.class);
        System.out.println("aggregation:" + search);
        System.out.println("aggregation result1:" + search.aggregations().get("group_by_age").lterms().buckets().array().get(0));
    }

    private static void getDocument(ElasticsearchClient client, String id) throws IOException {
        GetResponse<Employer> getResponse = client.get(q -> q
                        .index("employer-demo")
                        .id(id)
                , Employer.class);
        System.out.println("getDocument:" + getResponse);
    }

    private static void searchDocument(ElasticsearchClient client) throws IOException {
        SearchResponse<Employer> search = client.search(s -> s
                        .index("employer-demo")
                        .query(q -> q
                                .matchAll(ma -> ma))
                , Employer.class);
        System.out.println("searchDocument:" + search);
    }

    private static String addDocument(ElasticsearchClient client) throws IOException {
        MockConfig mockConfig =
                new MockConfig()
                        .subConfig("name")
                        .stringSeed(Fakers.names(10))

                        // 设置 age 的范围
                        .subConfig("age")
                        .intRange(18, 20)

                        .subConfig("zw")
                        .stringSeed(Fakers.zw(10))

                        .subConfig("gj")
                        .stringSeed(Fakers.gj(10))

                        .subConfig("joinDate")
                        .dateRange("2012-01-01", "2022-12-31")

                        .subConfig("xs")
                        .longRange(1000, 10000)

                        .globalConfig();

        Employer mock = JMockData.mock(Employer.class, mockConfig);
        mock.setDesc(null);
        IndexResponse index = client.index(idx -> idx
                .index("employer-demo")
                .document(mock)
        );

        System.out.println("addDocument:" + index);
        return index.id();
    }

    private static void deleteIndex(ElasticsearchClient client) throws IOException {
        DeleteAliasResponse deleteAliasResponse = client.indices().deleteAlias(c -> c.index("_all").name("employer-demo"));
        System.out.println("deleteAlias:" + deleteAliasResponse.toString());
        DeleteIndexResponse delete = client.indices().delete(c -> c.index("employer-1"));
        System.out.println("deleteIndex:" + delete.toString());
    }

    private static void createIndex(ElasticsearchClient client) throws IOException {
        CreateIndexResponse createIndexResponse = client.indices()
                .create(c -> c.index("employer-1")
                        .aliases("employer-demo", alias -> alias)
                        .settings(settings -> settings
                                .numberOfShards("5")
                                .numberOfReplicas("2")
                                .refreshInterval(ri -> ri.time("1s"))
                        )
                        // 写法2
                        .mappings(br -> br.properties(Map.of(
                                        // 姓名
                                        "name", Property.of(prop -> prop.keyword(keywordProp -> keywordProp
                                                .index(true)
                                                .nullValue("未命名"))),
                                        // 年龄
                                        "age", Property.of(prop -> prop.integer(integerProp -> integerProp
                                                .nullValue(-1))),
                                        // 职位
                                        "zw", Property.of(prop -> prop.keyword(keywordProp -> keywordProp
                                                .index(true)
                                                .nullValue("员工"))),
                                        // 国家
                                        "gj", Property.of(prop -> prop.keyword(keywordProp -> keywordProp
                                                .index(true)
                                                .nullValue("中国"))),
                                        // 入职时间
                                        "joinDate", Property.of(prop -> prop.date(dateProp -> dateProp
                                                .index(true))),
                                        // 薪资
                                        "xs", Property.of(prop -> prop.long_(longProp -> longProp
                                                .index(true)
                                                .nullValue(0L)))
                                ))
                        )
                        .mappings(br -> br
                                // 姓名
                                .properties("name", prop -> prop.keyword(keywordProp -> keywordProp
                                        .index(true)
                                        .nullValue("未命名")))
                                // 年龄
                                .properties("age", prop -> prop.integer(integerProp -> integerProp
                                        .nullValue(-1)))
                                // 职位
                                .properties("zw", prop -> prop.keyword(keywordProp -> keywordProp
                                        .index(true)
                                        .nullValue("员工")))
                                // 国家
                                .properties("gj", prop -> prop.keyword(keywordProp -> keywordProp
                                        .index(true)
                                        .nullValue("中国")))
                                // 入职时间
                                .properties("joinDate", prop -> prop.date(dateProp -> dateProp
                                        .index(true)))
                                // 薪资
                                .properties("xs", prop -> prop.long_(longProp -> longProp
                                        .index(true)
                                        .nullValue(0L)))
                        )
                );
        System.out.println("createIndex:" + createIndexResponse.toString());
    }

    @Data
    public static class Employer {
        private long id;
        /**
         * 姓名
         */
        private String name;
        /**
         * 年龄
         */
        private Integer age;
        /**
         * 职位
         */
        private String zw;
        /**
         * 国家
         */
        private String gj;
        /**
         * 入职日期
         */
        private LocalDate joinDate;
        /**
         * 薪水
         */
        private Long xs;
        /**
         * desc
         */
        private String desc;
    }

}
